package ws.jdbc.concurrent.driver.sqlserver.tds;

import java.io.IOException;
import java.nio.ByteBuffer;
import ws.jdbc.concurrent.driver.sqlserver.tds.datastreamtypes.US_VARCHAR;
import ws.jdbc.concurrent.driver.sqlserver.tds.datastreamtypes.L_VARBYTE;
import ws.jdbc.concurrent.driver.sqlserver.tds.datastreamtypes.US_VARBYTE;
import ws.jdbc.concurrent.driver.sqlserver.tds.datastreamtypes.B_VARBYTE;
import ws.jdbc.concurrent.driver.sqlserver.tds.datastreamtypes.B_VARCHAR;

/**
 * This class stream a variable-length data stream reader.
 *
 * <i>
 * "Variable-length data streams consist of a stream of characters or a stream
 * of bytes. The two types are similar, in that they both have a length rule
 * and a data rule."
 * </i>
 *
 * @author Wilson Santos, 36228 <wilson.santos@ua.pt>
 */
public class VariableLengthDataStreamReader extends StreamReader {

  /**
   * Create a new reader instance.
   *
   * @param stream data input stream to read the token from.
   */
  public VariableLengthDataStreamReader(ByteBuffer stream) {
    super(stream);
  }

  B_VARBYTE readBVarByte() throws IOException {
    final int length = stream.get();
    bytesRead += 1;

    return new B_VARBYTE((byte) length, read(length));
  }

  B_VARCHAR readBVarChar() throws IOException {
    final int length = 2 * stream.get(); // the lengths of B_VARCHAR and US_VARCHAR
    // are given in Unicode (2 byte) characters.
    bytesRead += 1;

    return new B_VARCHAR((byte) length, read(length));
  }

  US_VARBYTE readUSVarByte() throws IOException {
    final int length = stream.getShort();
    bytesRead += 2;

    return new US_VARBYTE((short) length, read(length));
  }

  US_VARCHAR readUSVarChar() throws IOException {
    final int length = 2 * stream.getShort(); // the lengths of B_VARCHAR and US_VARCHAR
    // are given in Unicode (2 byte) characters.
    bytesRead += 2;

    return new US_VARCHAR((short) length, read(length));
  }

  L_VARBYTE readLVarByte() throws IOException {
    final int length = stream.getInt();
    bytesRead += 4;

    return new L_VARBYTE(length, read(length));
  }

  private byte[] read(int length) throws IOException {
    final byte[] data = new byte[length];
    stream.get(data, 0, length);
    bytesRead += length;

    return data;
  }
}
